#include "TextureManager.h"
#include <d3d9.h>
#include <d3dx9.h>

TextureManager TextureManager::Instance;

TextureManager::TextureManager(void)
{
	// no textures loaded, count is 0
	currentCount = 0;
	
	// used to determine what the next texture id is
	nextID = 0;

	// clear out the textureItem stucts
	for (int i=0; i<MAX_TEXTURES; i++)
	{
		textureItems[i].texture = NULL;

		textureItems[i].loaded = false;
		textureItems[i].textureID = -1;
		textureItems[i].filename[0] = '\0';
	}
}

TextureManager::~TextureManager(void)
{
	// make sure the textureManager is empty
	if (currentCount != 0)
	{
		ReleaseAll();
	}
}

/// Init - inits the textureManager object and stores off a copy
/// of the IDirect3DDevice9 object
bool TextureManager::Init(IDirect3DDevice9 *device)
{
	if (device == NULL)
	{
		return false;
	}

	// save a copy of the d3ddevice
	this->device = device;

	return true;
}

/// Shutdown - releases all textureItems and closes out the textureManager
void TextureManager::Shutdown()
{
	ReleaseAll();
}

/// ReleaseAll - provides access to release all the textureItems
void TextureManager::ReleaseAll()
{
	for (int i=0; i<MAX_TEXTURES; i++)
	{
		if (textureItems[i].texture != NULL)
		{
			textureItems[i].texture->Release();
			textureItems[i].texture = NULL;

			textureItems[i].loaded = false;
			textureItems[i].textureID = -1;
			textureItems[i].filename[0] = '\0';

			currentCount--;
		}
	}

	// check that currentCount is 0
}

/// LoadTexture - loads in a new texture if it doesn't already exist, otherwise, passes 
/// back the ID of the existing texture
int TextureManager::LoadTexture(const char *filename)
{
	// make sure the texture isn't in the cache already
	int textureID = DoesTextureExist(filename);

	// if it's not in here
	if (textureID == -1)
	{
		// make sure we have a spot to load to
		int spotID = FindFirstEmpty();
		if (spotID != -1)
		{
			// not found, load it
			// the IDirect3DTexture9 does not get release here and will be released later
			IDirect3DTexture9 *texture = NULL;
			HRESULT hr = D3DXCreateTextureFromFile(device, filename, &texture);
			if (hr == S_OK)
			{
				// init a new textureItem
				strncpy_s(textureItems[spotID].filename, filename, 32);
				textureItems[spotID].loaded = true;
				textureItems[spotID].texture = texture;
				textureItems[spotID].textureID = nextID;

				// increment the number of textures in the manager
				currentCount++;

				// increment the id to use for the next texture
				nextID++;

				return textureItems[spotID].textureID;
			}
		}
	}
	else
	{
		// we found it, return the ID
		return textureID;
	}

	// can't load texture
	return -1;
}

int TextureManager::LoadTextureInMemory( const char *filename, void* pSrcData, unsigned int SrcDataSize ) 
{
	// make sure the texture isn't in the cache already
	int textureID = DoesTextureExist(filename);

	// if it's not in here
	if (textureID == -1)
	{
		// make sure we have a spot to load to
		int spotID = FindFirstEmpty();
		if (spotID != -1)
		{
			// not found, load it
			// the IDirect3DTexture9 does not get release here and will be released later
			IDirect3DTexture9 *texture = NULL;
			HRESULT hr = D3DXCreateTextureFromFileInMemory(device, pSrcData, SrcDataSize, &texture);
			if (hr == S_OK)
			{
				// init a new textureItem
				strncpy_s(textureItems[spotID].filename, filename, 32);
				textureItems[spotID].loaded = true;
				textureItems[spotID].texture = texture;
				textureItems[spotID].textureID = nextID;

				// increment the number of textures in the manager
				currentCount++;

				// increment the id to use for the next texture
				nextID++;

				return textureItems[spotID].textureID;
			}
		}
	}
	else
	{
		// we found it, return the ID
		return textureID;
	}

	// can't load texture
	return -1;
}

/// GetTextureByID - returns a d3d texture object from the cache
IDirect3DTexture9 *TextureManager::GetTextureByID(int id)
{
	// does the file already exist?
	for (int i=0; i<MAX_TEXTURES; i++)
	{
		if (textureItems[i].textureID == id)
		{
			// found it
			return textureItems[i].texture;
		}
	}

	return 0;
}

/// ReleaseTextureByID - releases a specific texture from the cache by id
void TextureManager::ReleaseTextureByID(int id)
{
	for (int i=0; i<MAX_TEXTURES; i++)
	{
		if (textureItems[i].textureID == id)
		{
			textureItems[i].loaded = false;
			textureItems[i].texture->Release();
			textureItems[i].texture = NULL;
			textureItems[i].textureID = -1;
			textureItems[i].filename[0] = '\0';

			currentCount--;
		}
	}
}

// determines whether a texture exists in the manager
int TextureManager::DoesTextureExist(const char *filename)
{
	// does the file already exist?
	for (int i=0; i<MAX_TEXTURES; i++)
	{
		if (strcmp(textureItems[i].filename, filename) == 0)
		{
			// found it
			return textureItems[i].textureID;
		}
	}

	// not found
	return -1;
}

/// FindFirstEmpty - returns back the first empty slot in the texture manager
int TextureManager::FindFirstEmpty()
{
	for (int i=0; i<MAX_TEXTURES; i++)
	{
		// return the first empty spot
		if (!textureItems[i].loaded)
		{
			return i;
		}
	}

	// the list is full
	return -1;
}
